<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="SimpleSpring开发-AOP功能的设计与实现(4), 胡言乱语">
    <meta name="description" content="MySimpleSpring自研框架AOP实现前奏【实现AOP核心功能的前置知识】为什么需要AOP？AOP是什么？Spring实现的AOP的局限性？
IOC无法实现的功能：
对于OOP（面向对象）而言，一个功能是交由一个对象去进行的，从而把">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="referrer" content="no-referrer-when-downgrade">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    

    <title>SimpleSpring开发-AOP功能的设计与实现(4) | 胡言乱语</title>
    <link rel="icon" type="image/x-icon, image/vnd.microsoft.icon" href="/myblog/favicon.ico">

    <link rel="stylesheet" type="text/css" href="/myblog/libs/awesome/css/all.min.css">
    <link rel="stylesheet" type="text/css" href="/myblog/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/myblog/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/myblog/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/myblog/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/myblog/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/myblog/css/my.css">

    <script src="/myblog/libs/jquery/jquery-3.6.0.min.js"></script>

<meta name="generator" content="Hexo 6.2.0"></head>


<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/myblog/" class="waves-effect waves-light">
                    
                    <img src="/myblog/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">胡言乱语</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/myblog/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/myblog/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>标签</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/myblog/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>分类</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/myblog/archives" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>归档</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/myblog/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>关于</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/myblog/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">胡言乱语</div>
        <div class="logo-desc">
            
            Never really desperate, only the lost of the soul.
            
        </div>
    </div>

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/myblog/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/myblog/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			标签
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/myblog/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			分类
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/myblog/archives" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			归档
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/myblog/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			关于
		</a>
          
        </li>
        
        
    </ul>
</div>


        </div>

        
    </nav>

</header>

    



<div class="bg-cover pd-header post-cover" style="background-image: url('/myblog/medias/featureimages/17.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">SimpleSpring开发-AOP功能的设计与实现(4)</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/myblog/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        padding: 35px 0 15px 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        padding-bottom: 30px;
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/myblog/tags/%E5%90%8E%E7%AB%AF/">
                                <span class="chip bg-color">后端</span>
                            </a>
                        
                            <a href="/myblog/tags/%E9%80%A0%E8%BD%AE%E5%AD%90/">
                                <span class="chip bg-color">造轮子</span>
                            </a>
                        
                            <a href="/myblog/tags/Spring/">
                                <span class="chip bg-color">Spring</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                    <div class="post-cate">
                        <i class="fas fa-bookmark fa-fw icon-category"></i>
                        
                            <a href="/myblog/categories/SimpleSpring%E5%BC%80%E5%8F%91%E4%B8%93%E6%A0%8F/" class="post-category">
                                SimpleSpring开发专栏
                            </a>
                        
                    </div>
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2022-06-08
                </div>
                

                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-check fa-fw"></i>更新日期:&nbsp;&nbsp;
                    2022-06-08
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-file-word fa-fw"></i>文章字数:&nbsp;&nbsp;
                    8.9k
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-clock fa-fw"></i>阅读时长:&nbsp;&nbsp;
                    35 分
                </div>
                

                
                    <div id="busuanzi_container_page_pv" class="info-break-policy">
                        <i class="far fa-eye fa-fw"></i>阅读次数:&nbsp;&nbsp;
                        <span id="busuanzi_value_page_pv"></span>
                    </div>
				
            </div>
        </div>
        <hr class="clearfix">

        
        <!-- 是否加载使用自带的 prismjs. -->
        <link rel="stylesheet" href="/myblog/libs/prism/prism.min.css">
        

        
        <!-- 代码块折行 -->
        <style type="text/css">
            code[class*="language-"], pre[class*="language-"] { white-space: pre-wrap !important; }
        </style>
        

        <div class="card-content article-card-content">
            <div id="articleContent">
                <h1 id="MySimpleSpring"><a href="#MySimpleSpring" class="headerlink" title="MySimpleSpring"></a>MySimpleSpring</h1><h2 id="自研框架AOP实现前奏【实现AOP核心功能的前置知识】"><a href="#自研框架AOP实现前奏【实现AOP核心功能的前置知识】" class="headerlink" title="自研框架AOP实现前奏【实现AOP核心功能的前置知识】"></a>自研框架AOP实现前奏【实现AOP核心功能的前置知识】</h2><h3 id="为什么需要AOP？AOP是什么？Spring实现的AOP的局限性？"><a href="#为什么需要AOP？AOP是什么？Spring实现的AOP的局限性？" class="headerlink" title="为什么需要AOP？AOP是什么？Spring实现的AOP的局限性？"></a>为什么需要AOP？AOP是什么？Spring实现的AOP的局限性？</h3><ul>
<li><p>IOC无法实现的功能：</p>
<p>对于OOP（面向对象）而言，一个功能是交由一个对象去进行的，从而把 一个 <strong>业务需求</strong>分为多个对象去组合执行。</p>
<p>而IOC容器的作用：可以 <strong>通过低耦合低侵入的方式</strong> 使得对象与对象之间的关系更容易维护，</p>
<p>从而可以使得 <strong>业务需求</strong> 可以通过容器更好地分层，并更好地相互调用。</p>
<p>但是，对于 <strong>业务需求之外的 系统需求</strong>， IOC容器并不能很好地解决。</p>
<p>所谓的 <strong>系统需求</strong> 就是指的是： <strong>只有程序员才会去关心的需求，例如：添加日志、添加权限校验等， 这种需求基本与业务毫无关系</strong></p>
<p><strong>根据设计原则，我们不应该把 系统需求与业务需求的代码写在一块，而是应该把他们分开去写，让业务代码只关注业务需求，让系统需求代码只关注系统需求，从而实现两者的解耦合，然后通过某种方式进行组合，从而实现我们想要的功能。</strong></p>
<p><strong>而IOC容器，只是一个方便对象与对象之间关系的工具，我们无法实现两种需求对应的对象的解耦，毕竟IOC容器只是托管了我们项目中需要的对象，然后在需要时我们通过容器来获取，然后进行组合，但这样一来，我们的系统需求对应的对象和业务需求对应的对象，总是要被一起写在一个地方去进行的，这样也没有实现我们所谓的解耦合。</strong></p>
<p><strong>而且，一般系统需求都是通用的，例如：添加日志，不仅一个对象要添加日志，那么难道我们一个个去getBean然后组合吗？总归是不合理的。</strong></p>
</li>
<li><p>综上，我们的框架需要提供<strong>一个核心功能</strong>：</p>
<p><strong>我们可以把系统需求对应的那部分代码，抽象出来单独写，然后通过该功能，自动地把该系统需求实现，织入到我们需要添加额外系统需求的业务代码之中</strong></p>
<p>例如：</p>
<p>我们可以把 添加日志 的实现，单独写。然后我们通过框架提供的功能，把该添加日志的功能，自动地添加到 我们的Controller、Service等需要日志记录的业务代码之中去，而此时，开发Controller、Service这些业务代码时，我们根本无需去关心是怎么添加日志的，这样就实现了解耦合。</p>
</li>
<li><p>该核心功能，被称为：Aspect Oriented Programming ， 即：<strong>AOP</strong></p>
<p>在实现AOP核心功能之前，我们需要对AOP的专业术语进行统一：</p>
<ul>
<li>我们所说的额外的系统需求代码 &#x3D;&gt; <strong>Aspect切面， 一般是一个类</strong></li>
<li>我们所说的需要被织入的业务代码(的位置) &#x3D;&gt; <strong>Pointcut 切入点，一般是 某个类的某个方法、成员变量、构造函数等</strong></li>
<li>业务代码被织入的时机: 执行前,执行后, 返回后, 抛出异常后 &#x3D;&gt; <strong>Advice通知，一般是一个个方法，至于其时机的控制，交由框架去实现</strong></li>
</ul>
<p>所以，用上述术语再去描述一下我们的核心功能AOP，那就是：</p>
<p><strong>我们要单独编写Aspect切面类，指定该切面要织入的Pointcut切入点，同时编写切面类中的Advice方法来对应各个时机要额外添加的系统功能。</strong></p>
<p><strong>这样一来，框架就会根据Pointcut找到对应的位置，从而把Aspect切面中定义的Advice方法，在对应的时机进行调用。</strong></p>
</li>
<li><p>一个切入点上的单个Aspect的执行流程：</p>
<p><img src="/myblog/mdImage/image-20220607114948221.png" alt="image-20220607114948221"></p>
</li>
<li><p>一个切入点上的多个Aspect的执行流程：</p>
<p><img src="/myblog/mdImage/image-20220607115035605.png" alt="image-20220607115035605"></p>
</li>
<li><p><strong>Spring中的AOP：</strong></p>
<ul>
<li>spring中的IOC占主导地位， 所以AOP只能在OOP中集成，因此没有单独使用那么灵活。</li>
<li>因此<strong>Spring自身实现的AOP并未实现“AOP”这个概念下的所有功能，而只能支持 方法级别的连接点， 而不能支持AOP这个概念下的构造方法、成员变量等</strong>的连接点毕竟这样就能满足80%的开发需求了。</li>
<li>剩下的如果需要可以借助AspectJ来实现</li>
</ul>
</li>
</ul>
<h3 id="代理模式："><a href="#代理模式：" class="headerlink" title="代理模式："></a>代理模式：</h3><p>通过上面的分析，我们很容易就能想到一个设计模式： <strong>代理模式</strong></p>
<p><img src="/myblog/mdImage/image-20220607115632877.png" alt="image-20220607115632877"></p>
<ul>
<li><p>概念：</p>
<p>代理类和被代理类同属于一个接口或一个类，代理类会在被代理类的原功能基础上，进行 <strong>功能增强</strong> 或 <strong>控制访问</strong>，</p>
<p>而客户端对此过程无感，只觉得自己在使用原对象，实际上是在使用被代理后的代理对象</p>
</li>
<li><p>由上述概念，很明显，我们可以通过 <strong>代理</strong> 的方式， 把我们的Aspect的那些Advice，从而对Pointcut进行织入。</p>
<p>客户端可以觉得它在使用原Pointcut，实际上是在使用代理对象。这样一来，就能实现我们的AOP功能了。</p>
<p>也就是说：</p>
<p><strong>AOP 是通过 代理模式 进行实现的</strong></p>
</li>
<li><p>实现方法：</p>
<ul>
<li>静态代理</li>
<li>动态代理</li>
</ul>
</li>
</ul>
<h3 id="静态代理"><a href="#静态代理" class="headerlink" title="静态代理"></a>静态代理</h3><ul>
<li><p>概念：通过<strong>硬编码的方式</strong>，来对 <strong>实现了同一个接口</strong>的目标对象，进行代理，从而对其目标方法进行控制</p>
</li>
<li><p>代码实现：</p>
<p>被代理类：</p>
<p><img src="/myblog/mdImage/image-20220607130645877.png" alt="image-20220607130645877"></p>
<p>Aspect：</p>
<p><img src="/myblog/mdImage/image-20220607130758808.png" alt="image-20220607130758808"></p>
<p>测试：</p>
<p><img src="/myblog/mdImage/image-20220607130822110.png" alt="image-20220607130822110"></p>
<p>由上可见，对客户端而言，客户端只觉得自己是在用 ToCPay 的实例，并不知道自己调用的pay其实是被代理过的。</p>
</li>
<li><p>缺点：</p>
<p>根本原因在于：<strong>硬编码</strong>的方式：<strong>我们的代理类要和被代理类硬编码实现同一个接口</strong></p>
<ul>
<li>当被代理类的接口新增一个方法时，尽管我们是要对新方法也是一样的织入，但是还是得硬编码去写。</li>
<li>当要新增一个被代理类时，尽管我们对它的织入代码是完全一样的，也必须新建一个代理类去进行代理。</li>
<li>代理对象只服务于一种类型的对象，如果要服务多类型的对象，势必要为每一种对象都进行代理，静态代理在程序规模稍大时就无法胜任了。</li>
</ul>
<p>结合之前对于IOC的实现，我们就知道：<strong>要想实现框架级别的灵活性与扩展性，只能是动态的方式来实现我们的功能</strong></p>
</li>
</ul>
<h3 id="动态代理概念"><a href="#动态代理概念" class="headerlink" title="动态代理概念"></a>动态代理概念</h3><p>通过 <strong>反射（JDK动态代理）</strong> 或 <strong>操控字节码（CGLIB）</strong>的方式，在运行时动态地生成 代理类的字节码，并加载到JVM中去，并创建代理类对象，从而得以使用代理类对象。</p>
<h3 id="JDK动态代理"><a href="#JDK动态代理" class="headerlink" title="JDK动态代理"></a>JDK动态代理</h3><ul>
<li><p>概念：通过java.reflect包下的反射机制，实现动态代理的功能。</p>
</li>
<li><p>两个核心类：</p>
<ul>
<li>InvocationHandler接口：相当于我们之前的Aspect</li>
<li>Proxy类：用于往目标类中织入上述Aspect，生成代理类对象</li>
</ul>
</li>
<li><p>注意：</p>
<p><strong>【被代理的类】必须实现接口</strong></p>
</li>
<li><p>代码实现：</p>
<ul>
<li>定义InvocationHandler的实现类，并在invoke方法中编写Aspect的逻辑代码：<ul>
<li>有三个参数，proxy是生成的代理对象，method是被代理的方法，args是方法的参数列表</li>
</ul>
</li>
</ul>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 相当于Aspect</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PayInvocationHandler</span> <span class="token keyword">implements</span> <span class="token class-name">InvocationHandler</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">// 因为invoke中的参数,并没有目标对象,所以要想调用目标对象的原方法,即被代理方法,还是得传入</span>
    <span class="token class-name">Object</span> target<span class="token punctuation">;</span> 

    <span class="token keyword">public</span> <span class="token class-name">PayInvocationHandler</span><span class="token punctuation">(</span><span class="token class-name">Object</span> target<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>target <span class="token operator">=</span> target<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">Object</span> proxy<span class="token punctuation">,</span> <span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token function">before</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Object</span> res <span class="token operator">=</span> method<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 原方法</span>
        <span class="token function">after</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> res<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">// Before Advice:</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">before</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"支付前的操作"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token comment">// After Advice:</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">after</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"支付后的操作"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<ul>
<li>通过Proxy.newProxyInstance()生成代理类对象，并得以使用。</li>
</ul>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
    <span class="token class-name">ToCPay</span> target <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ToCPayImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">InvocationHandler</span> aspect <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PayInvocationHandler</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">ToCPay</span> proxy <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">ToCPay</span><span class="token punctuation">)</span> <span class="token class-name">Proxy</span><span class="token punctuation">.</span><span class="token function">newProxyInstance</span><span class="token punctuation">(</span>target<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> 	                        target<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getInterfaces</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>aspect<span class="token punctuation">)</span><span class="token punctuation">;</span>
    proxy<span class="token punctuation">.</span><span class="token function">pay</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li>
</ul>
<h3 id="CGLIB动态代理"><a href="#CGLIB动态代理" class="headerlink" title="CGLIB动态代理"></a>CGLIB动态代理</h3><ul>
<li><p>概念：内部主要封装了 <strong>ASM JAVA字节码操控框架</strong>，可以动态生成<strong>被代理类的子类</strong>以覆盖其非final的方法，<strong>并绑定钩子回调自定义拦截器</strong></p>
<p>​		   即：当被代理类对象的目标方法被调用时，就会回调该所谓的自定义拦截器，其实就是我们说的Aspect，来对目标方法进行织入。</p>
</li>
<li><p>两个核心类：</p>
<ul>
<li>MethodInterceptor接口：类似于前面JDK动态代理中InvocationHandler的作用，可以用于定义Aspect</li>
<li>Enhancer类：类似于前面JDK动态代理中的Proxy类，用于创建代理对象</li>
</ul>
</li>
<li><p><strong>【被代理类，有没有接口，都可以使用CGLIB】</strong></p>
</li>
<li><p>代码实现：</p>
<ul>
<li><p>定义MethodInterceptor接口的实现类，并在intercept方法中编写Aspect的逻辑代码：</p>
<ul>
<li>有四个参数，proxy是生成的代理对象，method是被代理的方法，args是方法的参数列表，methodProxy被代理的方法</li>
<li><strong>由于此处可以通过methodProxy.invokeSuper(proxy,args)直接调用原方法，所以此时并不需要像JDK动态代理那样传入被代理对象</strong></li>
</ul>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 相当于Aspect</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PayMethodInterceptor</span> <span class="token keyword">implements</span> <span class="token class-name">MethodInterceptor</span> <span class="token punctuation">&#123;</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">intercept</span><span class="token punctuation">(</span><span class="token class-name">Object</span> proxy<span class="token punctuation">,</span> <span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span> <span class="token class-name">MethodProxy</span> methodProxy<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token function">before</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Object</span> res <span class="token operator">=</span> methodProxy<span class="token punctuation">.</span><span class="token function">invokeSuper</span><span class="token punctuation">(</span>proxy<span class="token punctuation">,</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 可以直接调用原方法， 无需原对象</span>
        <span class="token function">after</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> res<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">// Before Advice:</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">before</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"支付前的操作"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token comment">// After Advice:</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">after</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"支付后的操作"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
</li>
<li><p>通过Enhancer.create()方法，创建代理对象并得以使用</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">ToCPay</span> toCPay <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">ToCPay</span><span class="token punctuation">)</span> <span class="token class-name">Enhancer</span><span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token class-name">ToCPayImpl</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span><span class="token keyword">new</span> <span class="token class-name">PayMethodInterceptor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
toCPay<span class="token punctuation">.</span><span class="token function">pay</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></li>
</ul>
</li>
</ul>
<h3 id="两种动态代理的对比"><a href="#两种动态代理的对比" class="headerlink" title="两种动态代理的对比"></a>两种动态代理的对比</h3><ul>
<li>实现机制：<ul>
<li>JDK动态代理：<strong>基于反射机制</strong>，要求被代理类<strong>必须实现接口</strong></li>
<li>CGLIB：<strong>基于ASM机制实现</strong>，生成<strong>被代理类的子类</strong>作为代理类</li>
</ul>
</li>
<li>优势：<ul>
<li>JDK：是JDK原生支持，在JVM中运行较为可靠，可以平滑地支持JDK版本的升级</li>
<li>CGLIB：被代理类无需实现接口，可以实现完全的无侵入代理。</li>
</ul>
</li>
</ul>
<h3 id="Spring的AOP底层机制"><a href="#Spring的AOP底层机制" class="headerlink" title="Spring的AOP底层机制"></a>Spring的AOP底层机制</h3><ul>
<li><p>JDK动态代理 与CGLIB 共存：</p>
<ul>
<li>当被代理对象有接口时，默认JDK动态代理实现</li>
<li>当被代理对象无接口时，则使用CGLIB实现</li>
</ul>
</li>
<li><p><strong>CGLIB可以实现 有接口或无接口的动态代理， 但是还是默认用JDK的原因</strong>：</p>
<p><strong>JDK不依赖其他package，是Jdk自身提供的，并且兼容性较好，性能也不差</strong></p>
</li>
</ul>
<h2 id="自研框架AOP核心功能的实现："><a href="#自研框架AOP核心功能的实现：" class="headerlink" title="自研框架AOP核心功能的实现："></a>自研框架AOP核心功能的实现：</h2><h3 id="AOP-1-0-版本"><a href="#AOP-1-0-版本" class="headerlink" title="AOP 1.0 版本"></a>AOP 1.0 版本</h3><h4 id="技术选型："><a href="#技术选型：" class="headerlink" title="技术选型："></a>技术选型：</h4><ul>
<li><p>自研框架只采用<strong>CGLIB来实现动态代理</strong>，因为不需要被代理类必须实现接口，相对灵活，编码也较方便。</p>
</li>
<li><p>Spring的Aspect几乎都是通过注解来实现的，有如下注解：</p>
<ul>
<li>@Aspect</li>
<li>@Order</li>
<li>@Before</li>
<li>@After</li>
<li>@AfterReturning</li>
</ul>
<p>……</p>
<p>但是，为了实现简单，我们仅仅使用@Aspect与@Order来标注Aspect类，剩下的那些注解主要是为了标注Advice方法，</p>
<p>我们通过 <strong>定义模板类，由子类，即：Aspect类实现钩子方法（类似于模板方法设计模式中的钩子方法）</strong> 来实现Advice方法即可</p>
</li>
</ul>
<h4 id="实现流程："><a href="#实现流程：" class="headerlink" title="实现流程："></a>实现流程：</h4><p>我们之前说MethodInterceptor接口的实现类，相当于一个切入点的Aspect，用于之后被Enhancer类进行织入。</p>
<p>但是，之前那个案例是：一个切入点只有一个Aspect，但在框架内，事情可没那么简单。</p>
<p>由1.8-前奏中的：</p>
<p><img src="/myblog/mdImage/image-20220607115035605.png" alt="image-20220607115035605"></p>
<p>我们就知道，<strong>在框架内，一个切入点是会有多个Aspect的！</strong></p>
<p>如果我们还是用一个MethodInterceptor接口的实现类来代表一个Aspect，很显然，该实现类被Enhancer类织入时，明显是不行的！</p>
<p>为什么？因为无法实现上述的时序执行逻辑！</p>
<p>所以，我们要转变前一个案例给我们带来的定式思维，一个MethodInterceptor接口的实现类应该是对应一个切入点，而不是一个Aspect，换句话说：</p>
<p><strong>一个切入点，一个MethodInterceptor接口的实现类，可能有多个Aspect</strong></p>
<p><strong>所以，思路很明确，我们应该额外定义一个个独立的Aspect，例如：日志记录Aspect，事务Aspect等，然后通过一个一个MethodInterceptor接口的实现类用一个List来存储这些Aspect，从而就能实现 代理逻辑 以及 上述的时序执行逻辑</strong></p>
<p>但是，<strong>有切面了还不够，还得用Enhancer把代理逻辑织入到被代理对象，从而创建代理对象，所以我们需要一个额外的类来专门把代理对象创建出来，并替换掉IOC容器里面的原对象，从而实现之后我们用的对象都是代理后的对象。</strong></p>
<p>综上，AOP的实现流程如下：</p>
<ul>
<li><p>创建AOP的注解@Aspect、@Order，并定义Aspect通用的骨架（即上述我们说的模板类）</p>
</li>
<li><p>创建一个MethodInterceptor接口的实现类，用于实现 代理逻辑 以及 多个Aspect时序</p>
</li>
<li><p>创建一个类，专门用于把代理逻辑织入到被代理对象从而创建出代理对象，并覆盖IOC容器的原对象</p>
</li>
</ul>
<h4 id="创建AOP的注解-Aspect、-Order，并定义Aspect通用的骨架（即上述我们说的模板类）"><a href="#创建AOP的注解-Aspect、-Order，并定义Aspect通用的骨架（即上述我们说的模板类）" class="headerlink" title="创建AOP的注解@Aspect、@Order，并定义Aspect通用的骨架（即上述我们说的模板类）"></a>创建AOP的注解@Aspect、@Order，并定义Aspect通用的骨架（即上述我们说的模板类）</h4><ul>
<li><p>注解：</p>
<p>我们此处的@Aspect与Spring中的不同，Spring是用@Pointcut来指定切入点的，而我们为了方便，<strong>直接在@Aspect中指定哪些类要被作为切入点。</strong></p>
<p>@Aspect</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Target</span><span class="token punctuation">(</span><span class="token class-name">ElementType</span><span class="token punctuation">.</span>TYPE<span class="token punctuation">)</span>
<span class="token annotation punctuation">@Retention</span><span class="token punctuation">(</span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">.</span>RUNTIME<span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token annotation punctuation">@interface</span> <span class="token class-name">Aspect</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/**
     * 被 该注解 标注的类就是需要被织入代理逻辑的切入点
     * @return
     */</span>
    <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Annotation</span><span class="token punctuation">></span></span> <span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>@Order</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Target</span><span class="token punctuation">(</span><span class="token class-name">ElementType</span><span class="token punctuation">.</span>TYPE<span class="token punctuation">)</span>
<span class="token annotation punctuation">@Retention</span><span class="token punctuation">(</span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">.</span>RUNTIME<span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token annotation punctuation">@interface</span> <span class="token class-name">Order</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/**
     * 优先级,
     * @return
     */</span>
    <span class="token keyword">int</span> <span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
</li>
<li><p>骨架DefaultAspect：</p>
</li>
</ul>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">DefaultAspect</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/**
     * 事前
     * @param targetClass
     * @param method
     * @param args
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">before</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass<span class="token punctuation">,</span> <span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span>

    <span class="token comment">/**
     * 事后拦截
     * @param targetClass
     * @param method
     * @param args
     * @param returnValue
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">afterReturning</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass<span class="token punctuation">,</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span><span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span><span class="token class-name">Object</span> returnValue<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">return</span> returnValue<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">/**
     *
     * @param targetClass
     * @param method
     * @param args
     * @param e
     * @throws Throwable
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">afterThrowing</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass<span class="token punctuation">,</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span><span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span><span class="token class-name">Throwable</span> e<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span><span class="token punctuation">&#125;</span>

<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>



<h4 id="创建一个MethodInterceptor接口的实现类，用于实现-代理逻辑-以及-多个Aspect时序"><a href="#创建一个MethodInterceptor接口的实现类，用于实现-代理逻辑-以及-多个Aspect时序" class="headerlink" title="创建一个MethodInterceptor接口的实现类，用于实现 代理逻辑 以及 多个Aspect时序"></a>创建一个MethodInterceptor接口的实现类，用于实现 代理逻辑 以及 多个Aspect时序</h4><ul>
<li><p>在实现流程中有分析：</p>
<p><strong>一个切入点，一个MethodInterceptor接口的实现类，可能有多个Aspect</strong></p>
<p><strong>所以，思路很明确，我们应该额外定义一个个独立的Aspect，例如：日志记录Aspect，事务Aspect等，然后通过一个一个MethodInterceptor接口的实现类用一个List来存储这些Aspect，从而就能实现 代理逻辑 以及 上述的时序执行逻辑</strong></p>
<p>所以，该实现类内部必须有一个List存储这些Aspect,同时我们说多个Aspect之间应该按时序执行,所以,我们必须把 Aspect的Order值与其关联起来,进行排序。</p>
<p>即：AspectInfo：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AspectInfo</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> orderIndex<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">DefaultAspect</span> aspectObject<span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>
</li>
<li><p>综上，MethodInterceptor接口的实现类应该如下实现：</p>
<ul>
<li>成员变量是：被代理类:targetClass ; Aspect列表List&lt;AspectInfo&gt; </li>
<li>方法: </li>
<li>要对List&lt;AspectInfo&gt; 进行Order的排序</li>
<li>要按照之前规定的多个Aspect的执行时序,来依次执行这些Aspect的before、afterReturning、afterThrowing方法</li>
<li>代码实现：</li>
</ul>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AspectListExecutor</span> <span class="token keyword">implements</span> <span class="token class-name">MethodInterceptor</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">//被代理的类</span>
    <span class="token keyword">private</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass<span class="token punctuation">;</span>
    <span class="token comment">//排好序的Aspect列表</span>
    <span class="token annotation punctuation">@Getter</span>
    <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> sortedAspectInfoList<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">AspectListExecutor</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass<span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoList<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>targetClass <span class="token operator">=</span> targetClass<span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>sortedAspectInfoList <span class="token operator">=</span> <span class="token function">sortAspectInfoList</span><span class="token punctuation">(</span>aspectInfoList<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">/**
     * 按照order的值进行升序排序，确保order值小的aspect先被织入
     *
     * @param aspectInfoList
     * @return
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> <span class="token function">sortAspectInfoList</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoList<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">Collections</span><span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span>aspectInfoList<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Comparator</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token annotation punctuation">@Override</span>
            <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">compare</span><span class="token punctuation">(</span><span class="token class-name">AspectInfo</span> o1<span class="token punctuation">,</span> <span class="token class-name">AspectInfo</span> o2<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                <span class="token comment">//按照值的大小进行升序排序</span>
                <span class="token keyword">return</span> o1<span class="token punctuation">.</span><span class="token function">getOrderIndex</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> o2<span class="token punctuation">.</span><span class="token function">getOrderIndex</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> aspectInfoList<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">// 核心代理逻辑</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">intercept</span><span class="token punctuation">(</span><span class="token class-name">Object</span> proxy<span class="token punctuation">,</span> <span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span> <span class="token class-name">MethodProxy</span> methodProxy<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">Object</span> returnValue <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">ValidationUtil</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span>sortedAspectInfoList<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            returnValue <span class="token operator">=</span> methodProxy<span class="token punctuation">.</span><span class="token function">invokeSuper</span><span class="token punctuation">(</span>proxy<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span> returnValue<span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token comment">// 1) 按照order的顺序升序执行完所有Aspect的before方法</span>
        <span class="token function">invokeBeforeAdvices</span><span class="token punctuation">(</span>method<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span><span class="token punctuation">&#123;</span>
            <span class="token comment">// 2)执行被代理类的方法</span>
            returnValue <span class="token operator">=</span> methodProxy<span class="token punctuation">.</span><span class="token function">invokeSuper</span><span class="token punctuation">(</span>proxy<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 3)如果被代理方法正常返回，则按照order的顺序降序执行完所有Aspect的afterReturning方法</span>
            returnValue <span class="token operator">=</span> <span class="token function">invokeAfterReturningAdvices</span><span class="token punctuation">(</span>method<span class="token punctuation">,</span> args<span class="token punctuation">,</span> returnValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            <span class="token comment">// 4) 如果被代理方法抛出异常，则按照order的顺序降序执行完所有Aspect的afterThrowing方法</span>
            <span class="token function">invokeAfterThrowingAdvices</span><span class="token punctuation">(</span>method<span class="token punctuation">,</span> args<span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token keyword">return</span> returnValue<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>


    <span class="token comment">//4.如果被代理方法抛出异常，则按照order的顺序降序执行完所有Aspect的afterThrowing方法</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">invokeAfterThrowingAdvices</span><span class="token punctuation">(</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span> <span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span>  sortedAspectInfoList<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">>=</span><span class="token number">0</span> <span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            sortedAspectInfoList<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAspectObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">afterThrowing</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span> method<span class="token punctuation">,</span> args<span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">//3.如果被代理方法正常返回，则按照order的顺序降序执行完所有Aspect的afterReturning方法</span>
    <span class="token keyword">private</span> <span class="token class-name">Object</span> <span class="token function">invokeAfterReturningAdvices</span><span class="token punctuation">(</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span> <span class="token class-name">Object</span> returnValue<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">Object</span> result <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span>  sortedAspectInfoList<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">>=</span><span class="token number">0</span> <span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            result <span class="token operator">=</span> sortedAspectInfoList<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAspectObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">afterReturning</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span> method<span class="token punctuation">,</span> args<span class="token punctuation">,</span> returnValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token keyword">return</span> result<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">//1.按照order的顺序升序执行完所有Aspect的before方法</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">invokeBeforeAdvices</span><span class="token punctuation">(</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token class-name">AspectInfo</span> aspectInfo <span class="token operator">:</span> sortedAspectInfoList<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            aspectInfo<span class="token punctuation">.</span><span class="token function">getAspectObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">before</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span> method<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li>
</ul>
<h4 id="创建一个类，专门用于把代理逻辑织入到被代理对象从而创建出代理对象，并覆盖IOC容器的原对象"><a href="#创建一个类，专门用于把代理逻辑织入到被代理对象从而创建出代理对象，并覆盖IOC容器的原对象" class="headerlink" title="创建一个类，专门用于把代理逻辑织入到被代理对象从而创建出代理对象，并覆盖IOC容器的原对象"></a>创建一个类，专门用于把代理逻辑织入到被代理对象从而创建出代理对象，并覆盖IOC容器的原对象</h4><ul>
<li><p>前情回顾:</p>
<ul>
<li><p>我们已经有了Aspect的模板类DefaultAspect，则用户定义的Aspect必须实现该模板类，并根据需要实现其before、afterReturning、afterThrowing方法</p>
</li>
<li><p>我们已经有了@Aspect注解, 通过该注解的值, 指定<strong>该值对应的注解所标注的类，就是我们的被代理类</strong></p>
</li>
<li><p>通过@Order的值, 来指定该Aspect的优先级</p>
</li>
<li><p>我们已经有了一个切入点所对应的一个MethodInterceptor接口的实现类AspectListExecutor，并帮我们实现了同一个切入点的Aspect列表的时序控制。</p>
</li>
</ul>
</li>
<li><p>实现流程</p>
<p>如今， 我们就是要借助上面的已经实现的类来实现AOP，我们可以采用逆序思维去考虑流程：</p>
<ul>
<li><p>首先，Enhancer要用AspectListExecutor来生成代理对象，那么我们就必须得对应一个切入点，有一个AspectListExecutor</p>
</li>
<li><p>而一个AspectListExecutor里面有一个targetClass，一个List&lt;AspectInfo&gt;</p>
</li>
<li><p>那么，对于List&lt;AspectInfo&gt;，我们可以从IOC容器中获得被@Aspect所标注的类，即：Aspect类，但是一个项目里有这么多Aspect，</p>
<p>我们肯定得先建立一个Map，把@Aspect注解里面的值相同的Aspect封装为AspectInfo然后放在同一个List里面</p>
</li>
<li><p>这样一来，List&lt;AspectInfo&gt;就有了，至于targetClass，我们要注意：**@Aspect里面的值，虽然是个class，但是并不是我们的targetClass，即：不是我们的被代理类Class对象，而只是一个 注解，例如@Controller、@Service等**， </p>
<p>所以， 我们得通过该注解， 从IOC容器中获得所有的被该注解标注的类的集合，从而遍历集合，这样一来，targetClass也有了，</p>
<p>我们就可以生成AspectListExecutor，然后通过Enhancer生成targetClass的代理类对象了</p>
</li>
<li><p>然后，我们就可以把这个代理类对象覆盖掉IOC容器中的原对象。至此AOP功能就完成了</p>
</li>
</ul>
<p>所以，顺着来看，我们的实现流程如下：</p>
<ul>
<li><p>通过IOC容器获得所有的被@Aspect所标注的类即：Aspect类 的集合</p>
</li>
<li><p>然后，我们遍历上述Aspect类集合，根据 其@Aspect注解中的value（即：一个注解），将其分类，从而得到一个Map&lt;注解, List&lt;AspectInfo&gt;</p>
</li>
<li><p>从而,我们就可以遍历该Map&lt;注解, List&lt;AspectInfo&gt;的keySet, 通过key:注解来获得IOC容器中所有被该注解修饰的类集合,遍历该类集合,对于每一个targetClass, 以及Map中该注解对应的List&lt;AspectInfo&gt;, 生成一个AspectListExecutor, 从而由Enhancer生成targetClass的代理类对象.</p>
<p>把该代理类对象存入IOC容器中覆盖原对象.</p>
</li>
</ul>
</li>
<li><p>代码实现:</p>
<p>AspectWeaver:</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/**
 * 实现AOP核心功能实现类
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AspectWeaver</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">// IOC容器</span>
    <span class="token keyword">private</span> <span class="token class-name">BeanContainer</span> beanContainer<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">AspectWeaver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>beanContainer <span class="token operator">=</span> <span class="token class-name">BeanContainer</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">/**
     * 执行AOP核心功能的方法
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doAop</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token comment">// 1) 获取所有的切面类</span>
        <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Class</span><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span><span class="token punctuation">></span></span> aspectSet <span class="token operator">=</span> beanContainer<span class="token punctuation">.</span><span class="token function">getClassesByAnnotation</span><span class="token punctuation">(</span><span class="token class-name">Aspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">ValidationUtil</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span>aspectSet<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span><span class="token keyword">return</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span>
        <span class="token comment">// 2) 遍历所有的切面类，对切面类进行分类</span>
        <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Class</span><span class="token punctuation">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Annotation</span><span class="token punctuation">></span><span class="token punctuation">,</span><span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span><span class="token punctuation">></span></span> categoryAspectMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> aspectClass <span class="token operator">:</span> aspectSet<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">verifyAspect</span><span class="token punctuation">(</span>aspectClass<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
                <span class="token function">categoryAspect</span><span class="token punctuation">(</span>categoryAspectMap<span class="token punctuation">,</span>aspectClass<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
                <span class="token comment">//不遵守规范则直接抛出异常</span>
                <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">RuntimeException</span><span class="token punctuation">(</span><span class="token string">"@Aspect and @Order must be added to the Aspect class, and Aspect class must extend from DefaultAspect"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">ValidationUtil</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span>categoryAspectMap<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token comment">// 3) 根据不同的织入目标，来进行织入</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Annotation</span><span class="token punctuation">></span></span> category <span class="token operator">:</span> categoryAspectMap<span class="token punctuation">.</span><span class="token function">keySet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token function">weaveByCategory</span><span class="token punctuation">(</span>category<span class="token punctuation">,</span>categoryAspectMap<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>category<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">weaveByCategory</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Annotation</span><span class="token punctuation">></span></span> category<span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoList<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token comment">// 1) 获得所有被category注解修饰的类集合</span>
        <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Class</span><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span><span class="token punctuation">></span></span> targetClasses <span class="token operator">=</span> beanContainer<span class="token punctuation">.</span><span class="token function">getClassesByAnnotation</span><span class="token punctuation">(</span>category<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 2) 遍历类集合,生成AspectListExecutor,并织入</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass <span class="token operator">:</span> targetClasses<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token class-name">AspectListExecutor</span> aspectListExecutor <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AspectListExecutor</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span> aspectInfoList<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">Object</span> proxyBean <span class="token operator">=</span> <span class="token class-name">ProxyCreator</span><span class="token punctuation">.</span><span class="token function">createProxy</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span> aspectListExecutor<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 3) 将生成的代理对象,覆盖原来IOC容器中的原对象</span>
            beanContainer<span class="token punctuation">.</span><span class="token function">addBean</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span>proxyBean<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">categoryAspect</span><span class="token punctuation">(</span><span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Class</span><span class="token punctuation">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">Annotation</span><span class="token punctuation">></span><span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span><span class="token punctuation">></span></span> categoryAspectMap<span class="token punctuation">,</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> aspectClass<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token comment">// 1) 获得该类上面修饰的Order注解的值</span>
        <span class="token class-name">Order</span> orderTag <span class="token operator">=</span> aspectClass<span class="token punctuation">.</span><span class="token function">getAnnotation</span><span class="token punctuation">(</span><span class="token class-name">Order</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Aspect</span> aspectTag <span class="token operator">=</span> aspectClass<span class="token punctuation">.</span><span class="token function">getAnnotation</span><span class="token punctuation">(</span><span class="token class-name">Aspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 2) 从IOC容器中获得该切面类</span>
        <span class="token class-name">DefaultAspect</span> defaultAspect <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">DefaultAspect</span><span class="token punctuation">)</span> beanContainer<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span>aspectClass<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 3) 将order值与切面类疯转为AspectInfo</span>
        <span class="token class-name">AspectInfo</span> aspectInfo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AspectInfo</span><span class="token punctuation">(</span>orderTag<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> defaultAspect<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 4) 将该aspectInfo加入到categoryAspectMap对应的注解值中去</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>categoryAspectMap<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>aspectTag<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            categoryAspectMap<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>aspectTag<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>aspectInfo<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
            <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            aspectInfoList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>aspectInfo<span class="token punctuation">)</span><span class="token punctuation">;</span>
            categoryAspectMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>aspectTag<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>aspectInfoList<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">//框架中一定要遵守给Aspect类添加@Aspect和@Order标签的规范，同时，必须继承自DefaultAspect.class</span>
    <span class="token comment">//此外，@Aspect的属性值不能是它本身</span>
    <span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">verifyAspect</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> aspectClass<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">return</span> aspectClass<span class="token punctuation">.</span><span class="token function">isAnnotationPresent</span><span class="token punctuation">(</span><span class="token class-name">Aspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
                aspectClass<span class="token punctuation">.</span><span class="token function">isAnnotationPresent</span><span class="token punctuation">(</span><span class="token class-name">Order</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
                <span class="token class-name">DefaultAspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">isAssignableFrom</span><span class="token punctuation">(</span>aspectClass<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li>
</ul>
<h3 id="AOP2-0版本-具备更精细化的切入点的AOP1-0"><a href="#AOP2-0版本-具备更精细化的切入点的AOP1-0" class="headerlink" title="AOP2.0版本: 具备更精细化的切入点的AOP1.0"></a>AOP2.0版本: 具备更精细化的切入点的AOP1.0</h3><h4 id="AOP1-0的短板"><a href="#AOP1-0的短板" class="headerlink" title="AOP1.0的短板:"></a>AOP1.0的短板:</h4><p>虽然我们的1.0版本基本实现了AOP的功能，但是我们是通过@Aspect里面的value 来指定 <strong>一个注解, 即: 被该注解所标注的类就是切入点</strong>.</p>
<p>这样很明显, 切入点的粒度太大了, 参考Spring的AOP, 是通过@Pointcut里面的表达式来实现方法级别的粒度的切入点的,</p>
<p>所以, <strong>我们必须在AOP1.0的基础上, 实现更精细化的切入点</strong></p>
<h4 id="怎么实现-参考SpringAOP的发展史"><a href="#怎么实现-参考SpringAOP的发展史" class="headerlink" title="怎么实现? 参考SpringAOP的发展史:"></a>怎么实现? 参考SpringAOP的发展史:</h4><p>当年Spring在开发AOP时, 也面临了切入点粒度太大的问题, 秉着Spring一直以来的海纳百川的思想, 他们选择了 <strong>集成AspectJ</strong></p>
<p><strong>AspectJ框架: 提供了完整的AOP解决方案, 不仅包含注解、还包含ajc编译工具等，定义了切面语法以及切面语法的解析机制，提供了强大的织入工具，同时几乎支持所有级别的切入点，例如：方法级别、构造方法级别、成员变量级别等。</strong></p>
<p>但是，在Spring看来，其原先的 <strong>JDK动态代理&#x2F;CGLIB + IOC容器</strong> 的AOP实现机制,已经足以实现AOP功能了, <strong>他们缺少的仅仅只是更完美的切面语法</strong></p>
<p>因此, 出于节省用户的学习成本, 以及减少改造成本, <strong>Spring只在框架中集成了AspectJ中的切面语法, 用于实现更精细化的切入点控制</strong></p>
<p>同时, <strong>由于方法级别的切入点已经可以满足80%的Spring框架开发需求, 所以Spring也没有集成AspectJ的支持所有级别切入点的功能</strong></p>
<p>综上所述, 我们当前面临的处境其实是与Spring类似的，所以参考大公司的思路：我们也要使用最小的改造成本，换取最大的收益：</p>
<ul>
<li>仅仅引入<strong>AspectJ的切面表达式和相关的解析机制</strong></li>
<li><strong>只需要让Pointcut更加灵活以及精细</strong>，无需改变原有的AOP实现机制</li>
</ul>
<h4 id="AspectJ的两大核心类："><a href="#AspectJ的两大核心类：" class="headerlink" title="AspectJ的两大核心类："></a>AspectJ的两大核心类：</h4><ul>
<li><p>PointcutParser类： 通过其中的：parsePointcutExpression(String expression) 方法， 可以得到该字符串表达式对应的PointcutExpression类对象</p>
</li>
<li><p>PointcutExpression类：可以通过其中的：</p>
<ul>
<li><p>couldMatchJoinPointsInType(Class ) 判断当前targetClass是否符合表达式，</p>
<p>注意：该方法只支持within等某些表达式，不支持execution表达式（直接返回true），所以只能对Class进行粗筛</p>
</li>
<li><p>matcherMethodExecution(Method) 判断当前method是否符合表达式</p>
<p>该方法支持execution表达式，可以定位到method级别，所以是精筛</p>
</li>
</ul>
<p>​	考虑到性能问题，我们可以先进行一遍粗筛，把不符合表达式的Class先remove掉，之后再通过精筛去看看方法是否符合表达式</p>
<p> 很明显，通过以上两个类，我们就可以实现 切面语法 以及 切面语法的解析了。</p>
<p> 接下来，就是把上述两个类，整合到我们先前的逻辑里面了。</p>
</li>
</ul>
<h4 id="实现流程：-1"><a href="#实现流程：-1" class="headerlink" title="实现流程："></a>实现流程：</h4><ul>
<li><p>我们先前用**@Aspect**中的Class value 来指定注解, 如今为了方便植入AspectJ的pointcut逻辑,<strong>我们可以把value改成String, 来指定Pointcut表达式</strong></p>
</li>
<li><p>既然<strong>如今我们已经是使用Pointcut表达式, 是精确到各个类本身以及其方法级别的, 而不是简单的注解标注以及其所有方法的级别了.所以, 我们无法再对@Aspect进行分类为一个个List, 来表示他们是对一类Aspect了,然后对该注解下面的所有类都简单地直接传入AspectListExecutor进行创建</strong></p>
<p>所以, <strong>我们应该每个Aspect有自己的Pointcut的解析类, 来判断当前这个targetClass以及其method是否符合当前Aspect(即: 先粗筛后精筛),只有符合,才把该Aspect留到AspectListExecutor最后执行时序逻辑的那个List里面去进行织入</strong></p>
</li>
</ul>
<p>综上, 我们的实现流程如下:</p>
<ul>
<li><p>@Aspect中的value改成String类型, 来作为Pointcut表达式</p>
</li>
<li><p>创建PointcutLocator类, 使用上述AspectJ的两大核心类用于提供 <strong>对应的一个Pointcut表达式的判断机制</strong></p>
</li>
<li><p>把@Order的value值、DefaultAspect对象、PointcutLocator对象，组合成一个AspectInfo类</p>
<p>即：<strong>一个Aspect，对应一个Pointcut表达式，对应一个PointcutLocator进行判断</strong></p>
</li>
<li><p>实现AOP, 即: 在原doAOP中：</p>
<ul>
<li><p>先从IOC容器中获得所有的DefaultAspect类对象，对每一个DefaultAspect, 通过其@Aspect注解的Pointcut表达式，生成PointcutLocator，组合成一个AspectInfo对象</p>
<p>从而得到一个List&lt;AspectInfo&gt;。</p>
</li>
<li><p>从IOC容器中获得所有的Class类对象（除了DefaultAspect），对这些类对象进行遍历，</p>
<p>对每一个targetClass：</p>
<ul>
<li><p>遍历List&lt;AspectInfo&gt;，通过AspectInfo中的PointcutLocator的粗筛，判断该Aspect是否是该targetClass的切面，如果是存到一个新的List里面</p>
</li>
<li><p>以上遍历结束，则就会得到一个粗筛之后的List</p>
</li>
<li><p>但是还得进行精筛，精筛是需要Method的，只有AspectListExecutor类中的intercept方法才会有这个targetClass中的一个个方法，从而把这个List以及targetClass传入<strong>AspectListExecutor中，在intercept方法中进行精筛</strong>：</p>
<p><strong>遍历List&lt;AspectInfo&gt;，通过AspectInfo中的PointcutLocator的精筛，判断该Aspect是否是该Method的切面，如果不是那就remove掉。</strong></p>
<p>此时注意：</p>
<p>之前就说过：一个targetClass是对应一个AspectListExecutor，而Pointcut表达式是精细到方法级别的，在AspectListExecutor中的sortedList只是代表这些Aspect是该targetClass的切面，并不意味着这些Aspect是该targetClass所有方法的切面，所以要进行精筛把不是该Method的Aspect给去除掉然后再执行时序逻辑。但是同时，一个AspectListExecutor只对应一个sortedList，如果我们直接对该sortedList进行remove，那么其他Method很有可能就会失去他们的Aspect，举个例子：</p>
<p>Aspect1是方法A的切面，Aspect2是方法B的切面，两个都是targetClass的切面，所以被存入了同一个AspectListExecutor中的sortedList。</p>
<p>当我们的方法A被调用时，intercept方法会拦截同时进行代理，此时根据上述逻辑，我们遍历Aspect1和Aspect2，会发现Aspect2并不是方法A的切面，如果此时我们直接对原sortedList进行remove，那么当方法B被调用时，Aspect2就无了，就无法实现代理了。</p>
<p><strong>所以此时我们要考虑不在原sortedList上面操作，而是考虑使用一个副本(可以把逻辑改成: 如果是就加入到一个新List,从而把这个新List传入各个方法里面执行时序逻辑)来执行时序逻辑。此时sortedList的语义就发生了变化，其只是代表着是targetClass的切面，至于之后Method的时序控制，得对精筛后的list来进行</strong></p>
</li>
<li><p>至此,就有了AspectListExecutor了, 就可以通过Enhancer进行创建动态代理对象了, 从而就可以覆盖IOC容器中的原对象了</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="代码实现-根据上述流程-对1-0代码进行修改或重构"><a href="#代码实现-根据上述流程-对1-0代码进行修改或重构" class="headerlink" title="代码实现: 根据上述流程,对1.0代码进行修改或重构"></a>代码实现: 根据上述流程,对1.0代码进行修改或重构</h4><ul>
<li>@Aspect:</li>
</ul>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Target</span><span class="token punctuation">(</span><span class="token class-name">ElementType</span><span class="token punctuation">.</span>TYPE<span class="token punctuation">)</span>
<span class="token annotation punctuation">@Retention</span><span class="token punctuation">(</span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">.</span>RUNTIME<span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token annotation punctuation">@interface</span> <span class="token class-name">Aspect</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/**
     * 通过表达式表示切入点
     * @return
     */</span>
    <span class="token class-name">String</span> <span class="token function">pointcut</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 被 该注解 标注的类就是需要被织入代理逻辑的切入点
     * @return
     */</span>
    <span class="token comment">// Class&lt;? extends Annotation> value();</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<ul>
<li><p>PointcutLocator类:</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">org<span class="token punctuation">.</span>simpleframework<span class="token punctuation">.</span>aop</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>aspectj<span class="token punctuation">.</span>weaver<span class="token punctuation">.</span>tools<span class="token punctuation">.</span></span><span class="token class-name">PointcutExpression</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>aspectj<span class="token punctuation">.</span>weaver<span class="token punctuation">.</span>tools<span class="token punctuation">.</span></span><span class="token class-name">PointcutParser</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>aspectj<span class="token punctuation">.</span>weaver<span class="token punctuation">.</span>tools<span class="token punctuation">.</span></span><span class="token class-name">ShadowMatch</span></span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>reflect<span class="token punctuation">.</span></span><span class="token class-name">Method</span></span><span class="token punctuation">;</span>

<span class="token comment">/**
 * 解析Aspect表达式并且定位被织入的目标
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PointcutLocator</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">/**
     * Pointcut解析器，直接给它赋值上Aspectj的所有表达式，以便支持对众多表达式的解析
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">PointcutParser</span> pointcutParser<span class="token operator">=</span> <span class="token class-name">PointcutParser</span><span class="token punctuation">.</span><span class="token function">getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution</span><span class="token punctuation">(</span>
            <span class="token class-name">PointcutParser</span><span class="token punctuation">.</span><span class="token function">getAllSupportedPointcutPrimitives</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">/**
     * 表达式解析器
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">PointcutExpression</span> pointcutExpression<span class="token punctuation">;</span>
    <span class="token keyword">public</span> <span class="token class-name">PointcutLocator</span><span class="token punctuation">(</span><span class="token class-name">String</span> expression<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>pointcutExpression <span class="token operator">=</span> pointcutParser<span class="token punctuation">.</span><span class="token function">parsePointcutExpression</span><span class="token punctuation">(</span>expression<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">/**
     * 判断传入的Class对象是否是Aspect的目标代理类，即匹配Pointcut表达式(初筛)
     *
     * @param targetClass 目标类
     * @return 是否匹配
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">roughMatches</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token comment">// couldMatchJoinPointsInType比较坑，只能校验within</span>
        <span class="token comment">// 不能校验 (execution(精确到某个类除外), call, get, set)，面对无法校验的表达式，直接返回true</span>
        <span class="token keyword">return</span> pointcutExpression<span class="token punctuation">.</span><span class="token function">couldMatchJoinPointsInType</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    <span class="token comment">/**
     * 判断传入的Method对象是否是Aspect的目标代理方法，即匹配Pointcut表达式(精筛)
     * @param method
     * @return
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">accurateMatches</span><span class="token punctuation">(</span><span class="token class-name">Method</span> method<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token class-name">ShadowMatch</span> shadowMatch <span class="token operator">=</span> pointcutExpression<span class="token punctuation">.</span><span class="token function">matchesMethodExecution</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>shadowMatch<span class="token punctuation">.</span><span class="token function">alwaysMatches</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span> <span class="token keyword">else</span><span class="token punctuation">&#123;</span>
            <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
</li>
<li><p>AspectInfo类:</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@AllArgsConstructor</span>
<span class="token annotation punctuation">@Getter</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AspectInfo</span> <span class="token punctuation">&#123;</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> orderIndex<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">DefaultAspect</span> aspectObject<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">PointcutLocator</span> pointcutLocator<span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
</li>
<li><p>AspectListExecutor类:</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AspectListExecutor</span> <span class="token keyword">implements</span> <span class="token class-name">MethodInterceptor</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">//被代理的类</span>
    <span class="token keyword">private</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass<span class="token punctuation">;</span>
    <span class="token comment">//排好序的Aspect列表</span>
    <span class="token annotation punctuation">@Getter</span>
    <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> sortedAspectInfoList<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">AspectListExecutor</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass<span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoList<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>targetClass <span class="token operator">=</span> targetClass<span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>sortedAspectInfoList <span class="token operator">=</span> <span class="token function">sortAspectInfoList</span><span class="token punctuation">(</span>aspectInfoList<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">/**
     * 按照order的值进行升序排序，确保order值小的aspect先被织入
     *
     * @param aspectInfoList
     * @return
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> <span class="token function">sortAspectInfoList</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoList<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">Collections</span><span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span>aspectInfoList<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Comparator</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token annotation punctuation">@Override</span>
            <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">compare</span><span class="token punctuation">(</span><span class="token class-name">AspectInfo</span> o1<span class="token punctuation">,</span> <span class="token class-name">AspectInfo</span> o2<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                <span class="token comment">//按照值的大小进行升序排序</span>
                <span class="token keyword">return</span> o1<span class="token punctuation">.</span><span class="token function">getOrderIndex</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> o2<span class="token punctuation">.</span><span class="token function">getOrderIndex</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> aspectInfoList<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">// 核心代理逻辑</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">intercept</span><span class="token punctuation">(</span><span class="token class-name">Object</span> proxy<span class="token punctuation">,</span> <span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span> <span class="token class-name">MethodProxy</span> methodProxy<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">Object</span> returnValue <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token comment">// 1) 对sortedAspectInfoList进行精筛, 并把该方法的切面存入到一个新的List中</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoForCurMethodList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">AspectInfo</span> aspectInfo <span class="token operator">:</span> sortedAspectInfoList<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">if</span><span class="token punctuation">(</span>aspectInfo<span class="token punctuation">.</span><span class="token function">getPointcutLocator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">accurateMatches</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span><span class="token punctuation">)</span> aspectInfoForCurMethodList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>aspectInfo<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token comment">// 注意: 如果该方法没有切面, 那就直接调用其原方法, 而不是不调用</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">ValidationUtil</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span>aspectInfoForCurMethodList<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            returnValue <span class="token operator">=</span> methodProxy<span class="token punctuation">.</span><span class="token function">invokeSuper</span><span class="token punctuation">(</span>proxy<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span> returnValue<span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token comment">// 2) 按照order的顺序升序执行完所有Aspect的before方法</span>
        <span class="token function">invokeBeforeAdvices</span><span class="token punctuation">(</span>aspectInfoForCurMethodList<span class="token punctuation">,</span>method<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">try</span><span class="token punctuation">&#123;</span>
            <span class="token comment">// 3)执行被代理类的方法</span>
            returnValue <span class="token operator">=</span> methodProxy<span class="token punctuation">.</span><span class="token function">invokeSuper</span><span class="token punctuation">(</span>proxy<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 4)如果被代理方法正常返回，则按照order的顺序降序执行完所有Aspect的afterReturning方法</span>
            returnValue <span class="token operator">=</span> in  <span class="token function">vokeAfterReturningAdvices</span><span class="token punctuation">(</span>aspectInfoForCurMethodList<span class="token punctuation">,</span>method<span class="token punctuation">,</span> args<span class="token punctuation">,</span> returnValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            <span class="token comment">// 5) 如果被代理方法抛出异常，则按照order的顺序降序执行完所有Aspect的afterThrowing方法</span>
            <span class="token function">invokeAfterThrowingAdvices</span><span class="token punctuation">(</span>aspectInfoForCurMethodList<span class="token punctuation">,</span>method<span class="token punctuation">,</span> args<span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token keyword">return</span> returnValue<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>


    <span class="token comment">//4.如果被代理方法抛出异常，则按照order的顺序降序执行完所有Aspect的afterThrowing方法</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">invokeAfterThrowingAdvices</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoForCurMethodList<span class="token punctuation">,</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span> <span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span>  aspectInfoForCurMethodList<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">>=</span><span class="token number">0</span> <span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            aspectInfoForCurMethodList<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAspectObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">afterThrowing</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span> method<span class="token punctuation">,</span> args<span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">//3.如果被代理方法正常返回，则按照order的顺序降序执行完所有Aspect的afterReturning方法</span>
    <span class="token keyword">private</span> <span class="token class-name">Object</span> <span class="token function">invokeAfterReturningAdvices</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoForCurMethodList<span class="token punctuation">,</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span> <span class="token class-name">Object</span> returnValue<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">Object</span> result <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span>  aspectInfoForCurMethodList<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">>=</span><span class="token number">0</span> <span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            result <span class="token operator">=</span> aspectInfoForCurMethodList<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAspectObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">afterReturning</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span> method<span class="token punctuation">,</span> args<span class="token punctuation">,</span> returnValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token keyword">return</span> result<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">//1.按照order的顺序升序执行完所有Aspect的before方法</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">invokeBeforeAdvices</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoForCurMethodList<span class="token punctuation">,</span><span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token class-name">AspectInfo</span> aspectInfo <span class="token operator">:</span> aspectInfoForCurMethodList<span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
            aspectInfo<span class="token punctuation">.</span><span class="token function">getAspectObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">before</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span> method<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
</li>
<li><p>AspectWeaver类:</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">org<span class="token punctuation">.</span>simpleframework<span class="token punctuation">.</span>aop</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>simpleframework<span class="token punctuation">.</span>aop<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Aspect</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>simpleframework<span class="token punctuation">.</span>aop<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Order</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>simpleframework<span class="token punctuation">.</span>aop<span class="token punctuation">.</span>aspect<span class="token punctuation">.</span></span><span class="token class-name">AspectInfo</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>simpleframework<span class="token punctuation">.</span>aop<span class="token punctuation">.</span>aspect<span class="token punctuation">.</span></span><span class="token class-name">DefaultAspect</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>simpleframework<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">BeanContainer</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>simpleframework<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">ValidationUtil</span></span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Annotation</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token operator">*</span></span><span class="token punctuation">;</span>

<span class="token comment">/**
 * 实现AOP核心功能实现类
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AspectWeaver</span> <span class="token punctuation">&#123;</span>
    <span class="token comment">// IOC容器</span>
    <span class="token keyword">private</span> <span class="token class-name">BeanContainer</span> beanContainer<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">AspectWeaver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>beanContainer <span class="token operator">=</span> <span class="token class-name">BeanContainer</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token comment">/**
     * 执行AOP核心功能的方法
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doAop</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token comment">// 1) 获取所有的切面类</span>
        <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Class</span><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span><span class="token punctuation">></span></span> aspectSet <span class="token operator">=</span> beanContainer<span class="token punctuation">.</span><span class="token function">getClassesByAnnotation</span><span class="token punctuation">(</span><span class="token class-name">Aspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">ValidationUtil</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span>aspectSet<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token comment">// 2) 把所有的切面类都封装为AspectInfo, 从而得到List&lt;AspectInfo></span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoList <span class="token operator">=</span> <span class="token function">packAspectSetToAspectInfoList</span><span class="token punctuation">(</span>aspectSet<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 3) 从IOC容器中获得所有的Class,</span>
        <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Class</span><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span><span class="token punctuation">></span></span> classes <span class="token operator">=</span> beanContainer<span class="token punctuation">.</span><span class="token function">getClasses</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass <span class="token operator">:</span> classes<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">if</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">.</span><span class="token function">isAnnotationPresent</span><span class="token punctuation">(</span><span class="token class-name">Aspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">continue</span><span class="token punctuation">;</span>
            <span class="token comment">// 4) 对除了@Aspect修饰的以外, 都要作为targetClass进行切面筛选=>粗筛</span>
            <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> roughMatchesList <span class="token operator">=</span>  <span class="token function">roughMatches</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span>aspectInfoList<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 5) 粗筛后的roughMatchesList, 说明该List都是targetClass的切面, 所以要进行精筛</span>
            <span class="token comment">//    由于精筛在aspectListExecutor里面, 所以该方法可以直接织入</span>
            <span class="token function">weaveIfNecessary</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span>roughMatchesList<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">&#125;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">weaveIfNecessary</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass<span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> roughMatchesList<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token comment">// 通过两个参数生成aspectListExecutor</span>
        <span class="token class-name">AspectListExecutor</span> aspectListExecutor <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AspectListExecutor</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span>roughMatchesList<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 从而创建动态代理对象</span>
        <span class="token class-name">Object</span> proxyBean <span class="token operator">=</span> <span class="token class-name">ProxyCreator</span><span class="token punctuation">.</span><span class="token function">createProxy</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span> aspectListExecutor<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 覆盖IOC容器中的原对象</span>
        beanContainer<span class="token punctuation">.</span><span class="token function">addBean</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">,</span>proxyBean<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> <span class="token function">roughMatches</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> targetClass<span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoList<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> roughMatchesList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 对当前targetClass进行粗筛</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">AspectInfo</span> aspectInfo <span class="token operator">:</span> aspectInfoList<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>aspectInfo<span class="token punctuation">.</span><span class="token function">getPointcutLocator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">roughMatches</span><span class="token punctuation">(</span>targetClass<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                roughMatchesList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>aspectInfo<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token keyword">return</span> roughMatchesList<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>

    <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> <span class="token function">packAspectSetToAspectInfoList</span><span class="token punctuation">(</span><span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Class</span><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span><span class="token punctuation">></span></span> aspectSet<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AspectInfo</span><span class="token punctuation">></span></span> aspectInfoList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> aspect <span class="token operator">:</span> aspectSet<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
            <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token function">verifyAspect</span><span class="token punctuation">(</span>aspect<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
                <span class="token class-name">Order</span> orderTag <span class="token operator">=</span> aspect<span class="token punctuation">.</span><span class="token function">getAnnotation</span><span class="token punctuation">(</span><span class="token class-name">Order</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">Aspect</span> aspectTag <span class="token operator">=</span> aspect<span class="token punctuation">.</span><span class="token function">getAnnotation</span><span class="token punctuation">(</span><span class="token class-name">Aspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 获得当前Aspect对应的defaultAspect对象</span>
                <span class="token class-name">DefaultAspect</span> defaultAspect <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">DefaultAspect</span><span class="token punctuation">)</span> beanContainer<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span>aspect<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 获得当前Aspect对应的pointcutLocator对象</span>
                <span class="token class-name">PointcutLocator</span> pointcutLocator <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PointcutLocator</span><span class="token punctuation">(</span>aspectTag<span class="token punctuation">.</span><span class="token function">pointcut</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// 封装为AspectInfo对象</span>
                <span class="token class-name">AspectInfo</span> aspectInfo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AspectInfo</span><span class="token punctuation">(</span>orderTag<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>defaultAspect<span class="token punctuation">,</span>pointcutLocator<span class="token punctuation">)</span><span class="token punctuation">;</span>
                aspectInfoList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>aspectInfo<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span> <span class="token keyword">else</span> <span class="token punctuation">&#123;</span>
                <span class="token comment">//不遵守规范则直接抛出异常</span>
                <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">RuntimeException</span><span class="token punctuation">(</span><span class="token string">"@Aspect and @Order must be added to the Aspect class, and Aspect class must extend from DefaultAspect"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">&#125;</span>
        <span class="token punctuation">&#125;</span>
        <span class="token keyword">return</span> aspectInfoList<span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
    
    <span class="token comment">//框架中一定要遵守给Aspect类添加@Aspect和@Order标签的规范，同时，必须继承自DefaultAspect.class</span>
    <span class="token comment">//此外，@Aspect的属性值不能是它本身</span>
    <span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">verifyAspect</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">></span></span> aspectClass<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
        <span class="token keyword">return</span> aspectClass<span class="token punctuation">.</span><span class="token function">isAnnotationPresent</span><span class="token punctuation">(</span><span class="token class-name">Aspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
                aspectClass<span class="token punctuation">.</span><span class="token function">isAnnotationPresent</span><span class="token punctuation">(</span><span class="token class-name">Order</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
                <span class="token class-name">DefaultAspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">isAssignableFrom</span><span class="token punctuation">(</span>aspectClass<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li>
</ul>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结:"></a>总结:</h3><p><img src="/myblog/mdImage/image-20220608135201455.png" alt="image-20220608135201455"></p>
<p>至此，我们的AOP核心功能就实现了，其实主要分为以下三部分：</p>
<ul>
<li>注解：@Aspect用于标注Aspect类以及该Aspect的切入点，@Order用于指定该Aspect的时序优先级</li>
<li>DefaultAspect抽象类：通过钩子函数的方式，给所有Aspect进行一个模板定义，Aspect必须继承该类</li>
<li>AspectExecutor类：实现了CGLIB的MethodInterceptor接口, 用于实现对同一个targetClass进行切入的切面类的时序逻辑, 并交由Enhancer创建代理对象</li>
<li>PointcutLocator类：集成了AspectJ两个核心类：PointcutParser以及PointcutExpression，从而可以对targetClass以及method判断是否是该切面的切入点</li>
<li>AspectWeaver类：整合上述类，执行AOP核心逻辑，实现AOP功能</li>
</ul>
<p>同时，我们的逻辑是：</p>
<p><strong>一个切面，对应一个DefaultAspect类、对应一个@Aspect指定的pointcut，对应一个PointcutLocator类</strong></p>
<p><strong>一个动态代理对象，对应一个targetClass，对应一个AspectExecutor类，对应多个切面，且被代理的方法均有所不同</strong></p>
<p>以上，基本就是AOP的总结。</p>
<p>那么，我们如何在项目中<strong>初始化或启动 IOC与AOP功能呢？</strong>，只需执行以下代码：</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// 1) 先加载IOC容器</span>
<span class="token class-name">BeanContainer</span> beanContainer <span class="token operator">=</span> <span class="token class-name">BeanContainer</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
beanContainer<span class="token punctuation">.</span><span class="token function">loadBeans</span><span class="token punctuation">(</span><span class="token string">"com.mlming"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 2) 再AOP代理,把该代理的Bean均代理了，并覆盖原Bean</span>
<span class="token keyword">new</span> <span class="token class-name">AspectWeaver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">doAop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 3) 最后依赖注入</span>
<span class="token keyword">new</span> <span class="token class-name">DependencyInjector</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">doIOC</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>

<p>之后就可以通过IOC容器无感地使用代理对象了。</p>

                
            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        文章作者:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/myblog/about" rel="external nofollow noreferrer">Lin MingMing</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        文章链接:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="https://mlming.gitee.io/myblog/myblog/2022/06/08/simplespring-kai-fa-aop-gong-neng-de-she-ji-yu-shi-xian-4/">https://mlming.gitee.io/myblog/myblog/2022/06/08/simplespring-kai-fa-aop-gong-neng-de-she-ji-yu-shi-xian-4/</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        版权声明:
                    </i>
                </span>
                <span class="reprint-info">
                    本博客所有文章除特別声明外，均采用
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    许可协议。转载请注明来源
                    <a href="/myblog/about" target="_blank">Lin MingMing</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>复制成功，请遵循本文的转载规则</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">查看</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/myblog/tags/%E5%90%8E%E7%AB%AF/">
                                    <span class="chip bg-color">后端</span>
                                </a>
                            
                                <a href="/myblog/tags/%E9%80%A0%E8%BD%AE%E5%AD%90/">
                                    <span class="chip bg-color">造轮子</span>
                                </a>
                            
                                <a href="/myblog/tags/Spring/">
                                    <span class="chip bg-color">Spring</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/myblog/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="twitter,facebook,google,qq,qzone,wechat,weibo,douban,linkedin" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/myblog/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
        </div>
    </div>

    

    

    

    

    

    

    

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="far fa-dot-circle"></i>&nbsp;本篇
            </div>
            <div class="card">
                <a href="/myblog/2022/06/08/simplespring-kai-fa-aop-gong-neng-de-she-ji-yu-shi-xian-4/">
                    <div class="card-image">
                        
                        
                        <img src="/myblog/medias/featureimages/17.jpg" class="responsive-img" alt="SimpleSpring开发-AOP功能的设计与实现(4)">
                        
                        <span class="card-title">SimpleSpring开发-AOP功能的设计与实现(4)</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2022-06-08
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/myblog/categories/SimpleSpring%E5%BC%80%E5%8F%91%E4%B8%93%E6%A0%8F/" class="post-category">
                                    SimpleSpring开发专栏
                                </a>
                            
                            
                        </span>
                    </div>
                </div>

                
                <div class="card-action article-tags">
                    
                    <a href="/myblog/tags/%E5%90%8E%E7%AB%AF/">
                        <span class="chip bg-color">后端</span>
                    </a>
                    
                    <a href="/myblog/tags/%E9%80%A0%E8%BD%AE%E5%AD%90/">
                        <span class="chip bg-color">造轮子</span>
                    </a>
                    
                    <a href="/myblog/tags/Spring/">
                        <span class="chip bg-color">Spring</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/myblog/2022/06/05/zuo-ti-xin-de-fang-fa-lun-lian-biao-cao-zuo-4/">
                    <div class="card-image">
                        
                        
                        <img src="/myblog/medias/featureimages/22.jpg" class="responsive-img" alt="做题心得-方法论-链表操作(4)">
                        
                        <span class="card-title">做题心得-方法论-链表操作(4)</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2022-06-05
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/myblog/categories/%E5%81%9A%E9%A2%98%E5%BF%83%E5%BE%97%E4%B8%93%E6%A0%8F/" class="post-category">
                                    做题心得专栏
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/myblog/tags/%E7%AE%97%E6%B3%95/">
                        <span class="chip bg-color">算法</span>
                    </a>
                    
                    <a href="/myblog/tags/%E9%93%BE%E8%A1%A8/">
                        <span class="chip bg-color">链表</span>
                    </a>
                    
                    <a href="/myblog/tags/%E5%8F%8C%E6%8C%87%E9%92%88/">
                        <span class="chip bg-color">双指针</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>



<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/myblog/libs/codeBlock/codeBlockFuction.js"></script>


  <!-- 是否加载使用自带的 prismjs. -->
  <script type="text/javascript" src="/myblog/libs/prism/prism.min.js"></script>


<!-- 代码语言 -->

<script type="text/javascript" src="/myblog/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/myblog/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/myblog/libs/codeBlock/codeShrink.js"></script>



    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget card" style="background-color: white;">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;目录</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/myblog/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('0'),
            headingSelector: 'h2, h3, h4'
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>




    <footer class="page-footer bg-color">
    

    <div class="container row center-align"
         style="margin-bottom: 0px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            
                <span id="year">2022</span>
            
            <a href="/myblog/about" target="_blank">Lin MingMing</a>
            |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
            |&nbsp;Theme&nbsp;<a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">Matery</a>
            <br>
            
                &nbsp;<i class="fas fa-chart-area"></i>&nbsp;站点总字数:&nbsp;<span
                        class="white-color">31.5k</span>
            
            
            
                
            
            
                <span id="busuanzi_container_site_pv">
                &nbsp;|&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;
                    <span id="busuanzi_value_site_pv" class="white-color"></span>
            </span>
            
            
                <span id="busuanzi_container_site_uv">
                &nbsp;|&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;
                    <span id="busuanzi_value_site_uv" class="white-color"></span>
            </span>
            
            <br>

            <!-- 运行天数提醒. -->
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">
    <a href="https://gitee.com/mmwindy" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
        <i class="fab fa-github"></i>
    </a>



    <a href="mailto:1139380762@qq.com" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=1139380762" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 1139380762" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var searchFunc = function (path, search_id, content_id) {
        'use strict';
        $.ajax({
            url: path,
            dataType: "xml",
            success: function (xmlResponse) {
                // get the contents from search data
                var datas = $("entry", xmlResponse).map(function () {
                    return {
                        title: $("title", this).text(),
                        content: $("content", this).text(),
                        url: $("url", this).text()
                    };
                }).get();
                var $input = document.getElementById(search_id);
                var $resultContent = document.getElementById(content_id);
                $input.addEventListener('input', function () {
                    var str = '<ul class=\"search-result-list\">';
                    var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                    $resultContent.innerHTML = "";
                    if (this.value.trim().length <= 0) {
                        return;
                    }
                    // perform local searching
                    datas.forEach(function (data) {
                        var isMatch = true;
                        var data_title = data.title.trim().toLowerCase();
                        var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                        var data_url = data.url;
                        data_url = data_url.indexOf('/') === 0 ? data.url : '/' + data_url;
                        var index_title = -1;
                        var index_content = -1;
                        var first_occur = -1;
                        // only match artiles with not empty titles and contents
                        if (data_title !== '' && data_content !== '') {
                            keywords.forEach(function (keyword, i) {
                                index_title = data_title.indexOf(keyword);
                                index_content = data_content.indexOf(keyword);
                                if (index_title < 0 && index_content < 0) {
                                    isMatch = false;
                                } else {
                                    if (index_content < 0) {
                                        index_content = 0;
                                    }
                                    if (i === 0) {
                                        first_occur = index_content;
                                    }
                                }
                            });
                        }
                        // show search results
                        if (isMatch) {
                            str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                            var content = data.content.trim().replace(/<[^>]+>/g, "");
                            if (first_occur >= 0) {
                                // cut out 100 characters
                                var start = first_occur - 20;
                                var end = first_occur + 80;
                                if (start < 0) {
                                    start = 0;
                                }
                                if (start === 0) {
                                    end = 100;
                                }
                                if (end > content.length) {
                                    end = content.length;
                                }
                                var match_content = content.substr(start, end);
                                // highlight all keywords
                                keywords.forEach(function (keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    match_content = match_content.replace(regS, "<em class=\"search-keyword\">" + keyword + "</em>");
                                });

                                str += "<p class=\"search-result\">" + match_content + "...</p>"
                            }
                            str += "</li>";
                        }
                    });
                    str += "</ul>";
                    $resultContent.innerHTML = str;
                });
            }
        });
    };

    searchFunc('/myblog/search.xml', 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/myblog/libs/materialize/materialize.min.js"></script>
    <script src="/myblog/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/myblog/libs/aos/aos.js"></script>
    <script src="/myblog/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/myblog/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/myblog/js/matery.js"></script>

    

    

    <!-- 雪花特效 -->
    

    <!-- 鼠标星星特效 -->
     
        <script type="text/javascript">
            // 只在桌面版网页启用特效
            var windowWidth = $(window).width();
            if (windowWidth > 768) {
                document.write('<script type="text/javascript" src="/myblog/libs/others/star.js"><\/script>');
            }
        </script>
    

    

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    <script src="/myblog/libs/others/clicklove.js" async="async"></script>
    
    
    <script async src="/myblog/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    <!--腾讯兔小巢-->
    
    

    

    

    
    <script src="/myblog/libs/instantpage/instantpage.js" type="module"></script>
    

</body>

</html>
